package com.dd.stack.redis.service.inner.impl;

import com.dd.stack.common.util.Result;
import com.dd.stack.redis.config.exception.DomainException;
import com.dd.stack.redis.config.redisConfig.RedisKeyFactory;
import com.dd.stack.redis.mapper.DataObjectMapper;
import com.dd.stack.redis.pojo.DO.DataObjectDO;
import com.dd.stack.redis.service.cache.DataObjectCacheDecorator;
import com.dd.stack.redis.repository.DataObjectRepository;
import com.dd.stack.redis.service.cache.DataObjectCacheService;
import io.lettuce.core.RedisException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @Author liuxianmeng
 * @CreateTime 2025/1/8 23:11
 * @Description DataObjectServiceImpl
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DataObjectServiceImpl {

    private final RedisTemplate<String, Object> redisTemplate;
    private final DataObjectCacheService dataObjectCacheService;
    private final DataObjectRepository dataObjectRepository;
    private final DataObjectMapper dataObjectMapper;
    private final ThreadPoolTaskScheduler scheduler;

    public void addDataObject(DataObjectDO dataObjectDO) {
        List<Long> ids = Collections.singletonList(dataObjectDO.getId());
        List<DataObjectDO> existing = dataObjectMapper.selectByIds(ids);
        if (existing != null && !existing.isEmpty()) {
            throw new DomainException(500, "当前DataObjectDO已存在");
        }

        // 1. 先写数据库
        dataObjectRepository.add(dataObjectDO);

        // 2. 删除列表缓存（新增影响列表数据）
        redisTemplate.delete(RedisKeyFactory.allDataObjectsKey());
    }

    /**
     * 更新操作
     */
    public Result updateDataObject(DataObjectDO dataObjectDO) {
        try {
            // 1. 先删除相关缓存
            String singleKey = RedisKeyFactory.singleDataObjectKey(dataObjectDO.getId());
            redisTemplate.delete(
                    Arrays.asList(
                            singleKey,
                            RedisKeyFactory.allDataObjectsKey()
                    )
            );

            // 2. 再更新数据库
            dataObjectRepository.update(dataObjectDO);

            return Result.success();
        } catch (DataAccessException e) {
            log.error("数据库更新失败: {}", e.getMessage(), e);
            return Result.error(500, "数据库操作失败");
        } catch (RedisException e) {
            log.error("缓存更新失败: {}", e.getMessage(), e);
            // 缓存失败可降级处理
            return Result.success();
        } finally {
            // 3. 最后再删除一遍缓存（延迟双删） 延迟时间单位：毫秒
            String singleKey = RedisKeyFactory.singleDataObjectKey(dataObjectDO.getId());
            scheduler.schedule(() -> {
                redisTemplate.delete(
                        Arrays.asList(
                                singleKey,
                                RedisKeyFactory.allDataObjectsKey()
                        )
                );
                log.info("延迟删除缓存: {}", singleKey);
            }, Instant.ofEpochMilli(System.currentTimeMillis() + RedisKeyFactory.DELAY_MILLISECONDS));
        }
    }

    /**
     * 删除操作
     */
    public Result deleteDataObject(Long id) {
        try {
            // 1. 先删除数据库数据
            dataObjectRepository.delete(id);

            // 2. 删除相关缓存
            String singleKey = RedisKeyFactory.singleDataObjectKey(id);
            redisTemplate.delete(
                    Arrays.asList(
                            singleKey,
                            RedisKeyFactory.allDataObjectsKey()
                    )
            );
            return Result.success();
        } catch (DataAccessException e) {
            log.error("数据库删除失败: {}", e.getMessage(), e);
            return Result.error(500, "数据库操作失败");
        } catch (RedisException e) {
            log.error("缓存删除失败: {}", e.getMessage(), e);
            // 缓存失败可降级处理
            return Result.success();
        }
    }

    /****************************** 查询走缓存 ***************************/

    public DataObjectDO getById(Long id) {
        return dataObjectCacheService.getById(id);
    }

    public List<DataObjectDO> all() {
        return dataObjectCacheService.all();
    }
}
